package symbolClass;

import java.util.*;

/*
    负责对seg做封装
    seg里装了变量/过程
    单例模式设计
    2022-3-11-杨海南
 */
public class ParaMap {
    private int size;
    //顶部（当前块）的段
    private Segment topSegment = null;
    //将不同层次的代码块压成栈
    private final Stack<Segment> segmentStack = new Stack<>();
    private static final ParaMap paraMapInstance = new ParaMap();

    //单例-饿汉
    private ParaMap() {
    }

    public static ParaMap getParaMapInstance() {
        return paraMapInstance;
    }

    //重定向，移除栈顶
    public void relocation() {
        segmentStack.pop();
        topSegment = topSegment.getPrevSeg();
    }

    //移进栈顶
    public void location() {
        Segment newTopSeg = new Segment(topSegment);
        topSegment = newTopSeg;
        segmentStack.push(newTopSeg);
    }

    public int size() {
        return size;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    //是否有重名的，要求类型、变量、函数名不能重复
    public boolean containsSymbol(String symbolName) {
        return !containsVariable(symbolName) && !containsFunction(symbolName) && !containsType(symbolName);
    }

    //查看一下当前块有没有重名的（不能和当前块重名，但是可以和以前的块重名）
    public boolean topContainsSymbol(String symbolName) {
        return topSegment.containsSymbol(symbolName);
    }

    //是否存在变量
    public boolean containsVariable(String variableName) {
        Segment nowSearchSeg = topSegment;
        while (nowSearchSeg != null) {
            if (nowSearchSeg.containsVariable(variableName)) {
                return true;
            }
            nowSearchSeg = nowSearchSeg.getPrevSeg();
        }
        return false;
    }

    public boolean containsFunction(String functionName) {
        Segment nowSearchSeg = topSegment;
        while (nowSearchSeg != null) {
            if (nowSearchSeg.containsFunction(functionName)) {
                return true;
            }
            nowSearchSeg = nowSearchSeg.getPrevSeg();
        }
        return false;
    }

    public boolean containsType(String typeName) {
        Segment nowSearchSeg = topSegment;
        while (nowSearchSeg != null) {
            if (nowSearchSeg.containsType(typeName)) {
                return true;
            }
            nowSearchSeg = nowSearchSeg.getPrevSeg();
        }
        return false;
    }


    // 通过变量名获取变量
    public SymbolNode getVariable(String variableName) {
        Segment nowSearchSeg = topSegment;
        while (nowSearchSeg != null) {
            SymbolNode symbolNode = nowSearchSeg.getSymbol(variableName);
            if (symbolNode != null)
                return symbolNode;
            nowSearchSeg = nowSearchSeg.getPrevSeg();
        }
        return null;
    }

    // 通过函数名获取函数
    public FunctionNode getFunction(String functionName) {
        Segment nowSearchSeg = topSegment;
        while (nowSearchSeg != null) {
            FunctionNode functionNode = nowSearchSeg.getFunction(functionName);
            if (functionNode != null)
                return functionNode;
            nowSearchSeg = nowSearchSeg.getPrevSeg();
        }
        return null;
    }

    // 通过类型名获取类型
    public TypeDeclaNode getType(String typeName) {
        Segment nowSearchSeg = topSegment;
        while (nowSearchSeg != null) {
            TypeDeclaNode typeNode = nowSearchSeg.getType(typeName);
            if (typeNode != null)
                return typeNode;
            nowSearchSeg = nowSearchSeg.getPrevSeg();
        }
        return null;
    }

    //   在当前块新增一个变量
    public void putVariable(String variableName, SymbolNode symbolNode) {
        topSegment.addSymbol(variableName, symbolNode);
    }

    public void putFunction(String funcName, FunctionNode functionNode) {
        topSegment.addFunction(funcName, functionNode);
    }

    public void putType(String typeName, TypeDeclaNode typeNode) {
        topSegment.addType(typeName, typeNode);
    }

    public void clear() {
        segmentStack.clear();
        size = 0;
    }

    public Set variableSet() {
        HashSet<String> variableSet = new HashSet<>();
        Segment nowSearchSeg = topSegment;
        while (nowSearchSeg != null) {
            variableSet.addAll(topSegment.getVariableSet());
            nowSearchSeg = nowSearchSeg.getPrevSeg();
        }
        return variableSet;
    }


    public Set<Map.Entry> entrySet() {
        HashSet<SymbolNode> entrySet = new HashSet<>();
        Segment nowSearchSeg = topSegment;
        while (nowSearchSeg != null) {
            entrySet.addAll(nowSearchSeg.getEntrySet());
            nowSearchSeg = nowSearchSeg.getPrevSeg();
        }
        return null;
    }
}
